import subprocess
import tempfile
import os
import json
import time
import signal
from typing import Dict, List, Tuple
import traceback

class JudgeService:
    """代码评测服务"""
    
    def __init__(self):
        self.supported_languages = {
            'python': {
                'extension': '.py',
                'command': 'python',
                'timeout': 10000,  # 10秒，以毫秒为单位
                'memory_limit': 64  # 默认64MB内存限制
            },
            'cpp': {
                'extension': '.cpp',
                'command': 'g++',
                'compile_command': ['g++', '-o', '{output}', '{source}'],
                'run_command': './{executable}',
                'timeout': 5000,  # 5秒，以毫秒为单位
                'memory_limit': 128
            },
            'java': {
                'extension': '.java',
                'command': 'javac',
                'compile_command': ['javac', '{source}'],
                'run_command': 'java {class_name}',
                'timeout': 5000,  # 5秒，以毫秒为单位
                'memory_limit': 128
            }
        }
    
    def judge_submission(self, code: str, language: str, test_cases: List[Dict], 
                        time_limit: int = None, memory_limit: int = None) -> Dict:
        """
        评测代码提交
        
        Args:
            code: 代码内容
            language: 编程语言
            test_cases: 测试用例列表
            time_limit: 时间限制（毫秒）
            memory_limit: 内存限制（MB）
        
        Returns:
            评测结果字典
        """
        try:
            if language not in self.supported_languages:
                return {
                    'status': 'CE',
                    'error_message': f'不支持的编程语言: {language}',
                    'score': 0,
                    'max_score': len(test_cases) * 10 if test_cases else 0,
                    'test_cases': []
                }
            
            lang_config = self.supported_languages[language]
            
            # 使用传入的限制或默认值
            timeout = time_limit or lang_config['timeout']
            memory_limit = memory_limit or lang_config['memory_limit']
            
            # 创建临时目录
            temp_dir = tempfile.mkdtemp()
            try:
                # 准备代码文件
                source_file = self._prepare_source_file(code, language, temp_dir)
                
                # 编译代码（如果需要）
                compile_result = self._compile_code(source_file, language, temp_dir)
                if compile_result['status'] != 'success':
                    return {
                        'status': 'CE',
                        'error_message': compile_result['message'],
                        'score': 0,
                        'max_score': len(test_cases) * 10 if test_cases else 0,
                        'test_cases': []
                    }
                
                # 运行测试用例
                test_results = []
                total_score = 0
                max_score = len(test_cases) * 10  # 假设每个测试用例10分
                
                for i, test_case in enumerate(test_cases):
                    result = self._run_test_case(
                        source_file, language, test_case, 
                        timeout, memory_limit, temp_dir, i
                    )
                    test_results.append(result)
                    
                    if result['status'] == 'AC':
                        total_score += 10
                
                # 确定最终状态
                final_status = self._determine_final_status(test_results)
                
                return {
                    'status': final_status,
                    'score': total_score,
                    'max_score': max_score,
                    'test_cases': test_results,
                    'execution_time': max([r.get('execution_time', 0) for r in test_results]) if test_results else 0,
                    'memory_usage': max([r.get('memory_used', 0) for r in test_results]) if test_results else 0
                }
            finally:
                # 清理临时目录
                try:
                    import shutil
                    shutil.rmtree(temp_dir, ignore_errors=True)
                except:
                    pass
                
        except Exception as e:
            return {
                'status': 'RE',
                'error_message': f'评测系统错误: {str(e)}',
                'score': 0,
                'max_score': len(test_cases) * 10 if test_cases else 0,
                'test_cases': []
            }
    
    def _prepare_source_file(self, code: str, language: str, temp_dir: str) -> str:
        """准备源代码文件"""
        lang_config = self.supported_languages[language]
        extension = lang_config['extension']
        
        if language == 'java':
            # Java需要类名与文件名一致
            class_name = 'Solution'
            filename = f'{class_name}{extension}'
            # 确保代码包含类定义
            if 'class Solution' not in code:
                code = f'public class Solution {{\n{code}\n}}'
        else:
            filename = f'solution{extension}'
        
        file_path = os.path.join(temp_dir, filename)
        
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(code)
        
        return file_path
    
    def _compile_code(self, source_file: str, language: str, temp_dir: str) -> Dict:
        """编译代码"""
        if language == 'python':
            return {'status': 'success'}  # Python不需要编译
        
        lang_config = self.supported_languages[language]
        compile_command = lang_config.get('compile_command', [])
        
        if not compile_command:
            return {'status': 'success'}
        
        try:
            # 替换命令中的占位符
            if language == 'cpp':
                output_file = os.path.join(temp_dir, 'solution')
                cmd = [arg.replace('{output}', output_file).replace('{source}', source_file) 
                       for arg in compile_command]
            elif language == 'java':
                cmd = [arg.replace('{source}', source_file) for arg in compile_command]
            else:
                cmd = compile_command
            
            # 执行编译
            result = subprocess.run(
                cmd, 
                capture_output=True, 
                text=True, 
                cwd=temp_dir,
                timeout=10  # 编译超时10秒
            )
            
            if result.returncode == 0:
                return {'status': 'success'}
            else:
                return {
                    'status': 'error',
                    'message': f'编译错误: {result.stderr}'
                }
                
        except subprocess.TimeoutExpired:
            return {
                'status': 'error',
                'message': '编译超时'
            }
        except Exception as e:
            return {
                'status': 'error',
                'message': f'编译异常: {str(e)}'
            }
    
    def _run_test_case(self, source_file: str, language: str, test_case: Dict, 
                       timeout: int, memory_limit: int, temp_dir: str, test_index: int) -> Dict:
        """运行单个测试用例"""
        try:
            input_data = test_case.get('input', '')
            expected_output = test_case.get('output', '')
            
            # 准备运行命令
            run_command = self._prepare_run_command(source_file, language, temp_dir)
            
            # 运行程序
            start_time = time.time()
            
            try:
                # 使用subprocess.run而不是Popen
                result = subprocess.run(
                    run_command,
                    input=input_data,
                    capture_output=True,
                    text=True,
                    timeout=timeout/1000.0,  # 转换为秒
                    cwd=temp_dir
                )
                execution_time = (time.time() - start_time) * 1000  # 转换为毫秒
                
                # 处理输出
                actual_output = result.stdout.strip()
                error_output = result.stderr.strip()
                
                # 检查是否有错误
                if error_output and result.returncode != 0:
                    return {
                        'status': 'RE',
                        'input': input_data,
                        'expected_output': expected_output,
                        'actual_output': actual_output,
                        'error_message': error_output,
                        'execution_time': execution_time
                    }
                
                # 比较输出
                if self._compare_output(actual_output, expected_output):
                    return {
                        'status': 'AC',
                        'input': input_data,
                        'expected_output': expected_output,
                        'actual_output': actual_output,
                        'execution_time': execution_time
                    }
                else:
                    return {
                        'status': 'WA',
                        'input': input_data,
                        'expected_output': expected_output,
                        'actual_output': actual_output,
                        'execution_time': execution_time
                    }
                    
            except subprocess.TimeoutExpired:
                return {
                    'status': 'TLE',
                    'input': input_data,
                    'expected_output': expected_output,
                    'actual_output': '',
                    'error_message': 'Time Limit Exceeded',
                    'execution_time': timeout
                }
                
        except Exception as e:
            return {
                'status': 'RE',
                'input': test_case.get('input', ''),
                'expected_output': test_case.get('output', ''),
                'actual_output': '',
                'error_message': f'运行异常: {str(e)}',
                'execution_time': 0
            }
    
    def _prepare_run_command(self, source_file: str, language: str, temp_dir: str) -> List[str]:
        """准备运行命令"""
        lang_config = self.supported_languages[language]
        
        if language == 'python':
            # 使用绝对路径
            return ['python', os.path.abspath(source_file)]
        elif language == 'cpp':
            executable = os.path.join(temp_dir, 'solution')
            return [executable]
        elif language == 'java':
            class_name = 'Solution'
            return ['java', class_name]
        else:
            return []
    
    def _compare_output(self, actual: str, expected: str) -> bool:
        """比较输出结果"""
        # 去除首尾空白字符
        actual = actual.strip()
        expected = expected.strip()
        
        # 简单字符串比较
        return actual == expected
    
    def _determine_final_status(self, test_results: List[Dict]) -> str:
        """确定最终状态"""
        if not test_results:
            return 'RE'
        
        # 检查是否有编译错误
        if any(r['status'] == 'CE' for r in test_results):
            return 'CE'
        
        # 检查是否有运行时错误
        if any(r['status'] == 'RE' for r in test_results):
            return 'RE'
        
        # 检查是否有超时
        if any(r['status'] == 'TLE' for r in test_results):
            return 'TLE'
        
        # 检查是否全部通过
        if all(r['status'] == 'AC' for r in test_results):
            return 'AC'
        
        # 其他情况为部分正确
        return 'WA'
    
    def judge_choice_question(self, answer: str, correct_answer: str) -> Dict:
        """评测选择题"""
        is_correct = answer.strip().upper() == correct_answer.strip().upper()
        return {
            'status': 'AC' if is_correct else 'WA',
            'score': 10 if is_correct else 0,
            'max_score': 10,
            'answer': answer,
            'correct_answer': correct_answer
        }
    
    def judge_blank_question(self, answer: str, correct_answer: str) -> Dict:
        """评测填空题"""
        # 支持多个答案，用逗号分隔
        correct_answers = [ans.strip() for ans in correct_answer.split(',')]
        user_answers = [ans.strip() for ans in answer.split(',')]
        
        # 检查答案数量是否匹配
        if len(user_answers) != len(correct_answers):
            return {
                'status': 'WA',
                'score': 0,
                'max_score': 10,
                'answer': answer,
                'correct_answer': correct_answer
            }
        
        # 检查每个答案
        correct_count = 0
        for user_ans, correct_ans in zip(user_answers, correct_answers):
            if user_ans.lower() == correct_ans.lower():
                correct_count += 1
        
        score = int((correct_count / len(correct_answers)) * 10)
        is_correct = correct_count == len(correct_answers)
        
        return {
            'status': 'AC' if is_correct else 'WA',
            'score': score,
            'max_score': 10,
            'answer': answer,
            'correct_answer': correct_answer
        }
    
    def judge_short_answer(self, answer: str, correct_answer: str) -> Dict:
        """评测简答题（简单关键词匹配）"""
        # 这里可以实现更复杂的评分逻辑，比如关键词匹配
        # 目前使用简单的包含关系判断
        answer_lower = answer.lower()
        correct_lower = correct_answer.lower()
        
        # 简单的关键词匹配
        keywords = correct_lower.split()
        matched_keywords = sum(1 for keyword in keywords if keyword in answer_lower)
        
        if len(keywords) == 0:
            score = 10 if answer_lower == correct_lower else 0
        else:
            score = int((matched_keywords / len(keywords)) * 10)
        
        is_correct = score >= 8  # 80%以上算正确
        
        return {
            'status': 'AC' if is_correct else 'WA',
            'score': score,
            'max_score': 10,
            'answer': answer,
            'correct_answer': correct_answer
        }
